今天會透過 minting system 學習透過 IPFS 與 Smart Contract 實作一個鑄造 NFT 的系統
所謂的鑄造就是建立一個 NFT,除了需要透過 Smart Contract 設定唯一識別代號並且需要設定一個該 token 所對應的實體物件 URI 。
為了方便實作這邊把實際物件設定為數位圖片,並且把數位圖片放到 ipfs 之上產生 hash 做識別號
把這個識別號設定為 NFT 的 URI
IPFS 是一種分散式存儲系統技術,對每個存入的檔案內容產生唯一識別代號,特別的是這個識別帶會是根據檔案內容所產生出來的。
所以可以避免檔案被更換而 NFT 持有者卻不知道
這邊範例採用 nft.storage 這個專門放 NFT 數位資產的一個存儲服務是建構在 IPFS 之上的服務
這邊會採用 scaffold-eth 這個 Dapp 專案當作基底來建構 minting service
透過以下指令 clone 專案
git clone https://github.com/ipfs-shipyard/nft-school-examples
cd nft-school-examples/end-to-end
安裝所需套件
yarn install
使用以下指定在 local 模擬
yarn chain
這個指令執行之後為顯示以下這些 account 資訊
這時候打開另一個 terminal 使用以下指令發佈 NFTMinter Contract 到鏈上
yarn deploy
然後就會看到以下畫面
接著可以執行以下指令來執行 Dapp
yarn start
透過執行 mint 動作
讀取 mint 完的 id
這邊是透過 NFTMinter Smart Contract 來建立 NFT Token
NFTMinter Contract 如下
//SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
import "hardhat/console.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
contract NFTMinter is ERC721 {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
constructor(string memory tokenName, string memory symbol) ERC721(tokenName, symbol) {
_setBaseURI("ipfs://");
}
function mintToken(address owner, string memory metadataURI)
public
returns (uint256)
{
_tokenIds.increment();
uint256 id = _tokenIds.current();
_safeMint(owner, id);
_setTokenURI(id, metadataURI);
return id;
}
}
可以注意到這邊只需要紀錄 nft.storage 所產生 uri 到對應的 token id
所以每次鑄造都會產生一個唯一識別代號 tokenId 並且把 nft.storage 所產生的 uri 儲存下來
語法如下:
const client = new NFTStorage({ token: NFT_STORAGE_KEY });
const metadata = await client.store({
name,
description,
image,
});
// our smart contract already prefixes URIs with "ipfs://", so we remove it before calling the `mintToken` function
const metadataURI = metadata.url.href.replace(/^ipfs:\/\//, "");
// scaffold-eth's Transactor helper gives us a nice UI popup when a transaction is sent
const transactor = Transactor(provider, gasPrice);
const tx = await transactor(contract.mintToken(ownerAddress, metadataURI));
setStatus("Blockchain transaction sent, waiting confirmation...");
// Wait for the transaction to be confirmed, then get the token ID out of the emitted Transfer event.
const receipt = await tx.wait();
let tokenId = null;
for (const event of receipt.events) {
if (event.event !== 'Transfer') {
continue
}
tokenId = event.args.tokenId.toString();
break;
}
這個 Dapp 實踐了鑄造 NFTToken 並且把內容讀取出來